////////////////////////////////////////////////////////////////////////
// This file is part of the simpleSID framework 
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
//
// Copyright (c)Richard White, 2009
// See License.txt for a disclaimer of all warranties
// and licensing information

// SID SoundDlg.cpp : implementation file
//

#include "stdafx.h"
#include "SID Sound.h"
#include "SID SoundDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const Notes CSIDSoundDlg::SIDNotes[]  = {		{1, 12},
											{1, 28},
											{1, 45},
											{1, 62}, 
											{1, 81}, 
											{1, 102}, 
											{1, 123}, 
											{1, 145},
											{1, 169},
											{1, 195},
											{1, 221},
											{1, 250},
											{2, 24},
											{2, 56},
											{2, 90},
											{2, 125},
											{2, 163},
											{2, 204},
											{2, 246},
											{3, 35},
											{3, 83},
											{3, 134},
											{3, 187},
											{3, 244},
											{4, 48},
											{4, 112},
											{4, 180},
											{4, 251},
											{5, 71},
											{5, 152},
											{5, 237},
											{6, 71},
											{6, 167},
											{7, 12},
											{7, 119},
											{7, 233},
											{8, 97},
											{8, 225},
											{9, 104},
											{9, 247},
											{10, 143},
											{11, 48},
											{11, 218},
											{12, 143},
											{13, 78},
											{14, 24},
											{14, 239},
											{15, 210},
											{16, 195},
											{17, 195},
											{18, 209},
											{19, 239},
											{21, 31},
											{22, 96},
											{23, 181},
											{25, 30},
											{26, 156},
											{28, 49},
											{29, 223},
											{31, 165},
											{33, 135},
											{35, 134},
											{37, 162},
											{39, 223},
											{42, 62},
											{44, 193},
											{47, 107},
											{50, 60},
											{53, 57},
											{56, 99},
											{59, 190},
											{63, 75},
											{67, 15},
											{71, 12},
											{75, 69},
											{79, 191},
											{84, 125},
											{89, 131},
											{94, 214},
											{100, 121},
											{106, 115},
											{112, 119},
											{119, 124},
											{126, 151},
											{134, 30},
											{142, 24},
											{150, 139},
											{159, 126},
											{168, 250},
											{179, 6},
											{189, 172},
											{200, 243},
											{212, 230},
											{225, 143},
											{238, 248},
											{253, 46}	};

static int paSidCallback(const void *inputBuffer, void *outputBuffer,
                           unsigned long framesPerBuffer,
                          const PaStreamCallbackTimeInfo* timeInfo,
                           PaStreamCallbackFlags statusFlags,
                           void *userData )
{

	RWSID *mySid = (RWSID *)userData;
	float *out = (float *)outputBuffer;

	mySid->Render(out, framesPerBuffer, 65536);

	return 0;
}
// CSIDSoundDlg dialog




CSIDSoundDlg::CSIDSoundDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSIDSoundDlg::IDD, pParent)
	, m_mySid(44100.f)
	, m_strAttackDecay1(_T(""))
	, m_strAttackDecay2(_T(""))
	, m_strAttackDecay3(_T(""))
	, m_strFreqHi1(_T(""))
	, m_strFreqHi2(_T(""))
	, m_strFreqHi3(_T(""))
	, m_strFreqLo1(_T(""))
	, m_strFreqLo2(_T(""))
	, m_strFreqLo3(_T(""))
	, m_strPwHi1(_T(""))
	, m_strPwHi2(_T(""))
	, m_strPwHi3(_T(""))
	, m_strPwLo1(_T(""))
	, m_strPwLo2(_T(""))
	, m_strPwLo3(_T(""))
	, m_strSustainRelease1(_T(""))
	, m_strSustainRelease2(_T(""))
	, m_strSustainRelease3(_T(""))
	, m_strFcHi(_T(""))
	, m_strFcLo(_T(""))
	, m_strRes(_T(""))
	, m_strVol(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CSIDSoundDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_WAVE1, m_cmbWave1);
	DDX_Control(pDX, IDC_WAVE2, m_cmbWave2);
	DDX_Control(pDX, IDC_WAVE3, m_cmbWave3);
	DDX_Control(pDX, IDC_NOTES1, m_cmbNotes1);
	DDX_Control(pDX, IDC_NOTES2, m_cmbNotes2);
	DDX_Control(pDX, IDC_NOTES3, m_cmbNotes3);
	DDX_Control(pDX, IDC_FC, m_cmbFC);
	DDX_Control(pDX, IDC_MODE, m_cmbMode);
	DDX_Text(pDX, IDC_ATTACKDECAY1, m_strAttackDecay1);
	DDX_Text(pDX, IDC_ATTACKDECAY2, m_strAttackDecay2);
	DDX_Text(pDX, IDC_ATTACKDECAY3, m_strAttackDecay3);
	DDX_Text(pDX, IDC_FREQHI1, m_strFreqHi1);
	DDX_Text(pDX, IDC_FREQHI2, m_strFreqHi2);
	DDX_Text(pDX, IDC_FREQHI3, m_strFreqHi3);
	DDX_Text(pDX, IDC_FREQLO1, m_strFreqLo1);
	DDX_Text(pDX, IDC_FREQLO2, m_strFreqLo2);
	DDX_Text(pDX, IDC_FREQLO3, m_strFreqLo3);
	DDX_Text(pDX, IDC_PWHI1, m_strPwHi1);
	DDX_Text(pDX, IDC_PWHI2, m_strPwHi2);
	DDX_Text(pDX, IDC_PWHI3, m_strPwHi3);
	DDX_Text(pDX, IDC_PWLO1, m_strPwLo1);
	DDX_Text(pDX, IDC_PWLO2, m_strPwLo2);
	DDX_Text(pDX, IDC_PWLO3, m_strPwLo3);
	DDX_Text(pDX, IDC_SUSTAINRELEASE1, m_strSustainRelease1);
	DDX_Text(pDX, IDC_SUSTAINRELEASE2, m_strSustainRelease2);
	DDX_Text(pDX, IDC_SUSTAINRELEASE3, m_strSustainRelease3);
	DDX_Text(pDX, IDC_FCHI, m_strFcHi);
	DDX_Text(pDX, IDC_FCLO, m_strFcLo);
	DDX_Text(pDX, IDC_RES, m_strRes);
	DDX_Text(pDX, IDC_VOL, m_strVol);
}

BEGIN_MESSAGE_MAP(CSIDSoundDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_EN_CHANGE(IDC_FREQLO1, &CSIDSoundDlg::OnEnChangeFreqlo1)
	ON_EN_CHANGE(IDC_FREQHI1, &CSIDSoundDlg::OnEnChangeFreqhi1)
	ON_EN_CHANGE(IDC_PWLO1, &CSIDSoundDlg::OnEnChangePwlo1)
	ON_EN_CHANGE(IDC_PWHI1, &CSIDSoundDlg::OnEnChangePwhi1)
	ON_CBN_SELCHANGE(IDC_NOTES1, &CSIDSoundDlg::OnCbnSelchangeNotes1)
	ON_CBN_SELCHANGE(IDC_WAVE1, &CSIDSoundDlg::OnCbnSelchangeWave1)
	ON_BN_CLICKED(IDC_GATE1, &CSIDSoundDlg::OnBnClickedGate1)
	ON_BN_CLICKED(IDC_SYNC1, &CSIDSoundDlg::OnBnClickedSync1)
	ON_BN_CLICKED(IDC_RINGMOD1, &CSIDSoundDlg::OnBnClickedRingmod1)
	ON_BN_CLICKED(IDC_TEST1, &CSIDSoundDlg::OnBnClickedTest1)
	ON_EN_CHANGE(IDC_ATTACKDECAY1, &CSIDSoundDlg::OnEnChangeAttackdecay1)
	ON_EN_CHANGE(IDC_SUSTAINRELEASE1, &CSIDSoundDlg::OnEnChangeSustainrelease1)
	ON_BN_CLICKED(IDC_RESET1, &CSIDSoundDlg::OnBnClickedReset1)
	ON_EN_CHANGE(IDC_FREQLO2, &CSIDSoundDlg::OnEnChangeFreqlo2)
	ON_EN_CHANGE(IDC_FREQHI2, &CSIDSoundDlg::OnEnChangeFreqhi2)
	ON_EN_CHANGE(IDC_PWLO2, &CSIDSoundDlg::OnEnChangePwlo2)
	ON_EN_CHANGE(IDC_PWHI2, &CSIDSoundDlg::OnEnChangePwhi2)
	ON_CBN_SELCHANGE(IDC_NOTES2, &CSIDSoundDlg::OnCbnSelchangeNotes2)
	ON_CBN_SELCHANGE(IDC_WAVE2, &CSIDSoundDlg::OnCbnSelchangeWave2)
	ON_BN_CLICKED(IDC_GATE2, &CSIDSoundDlg::OnBnClickedGate2)
	ON_BN_CLICKED(IDC_SYNC2, &CSIDSoundDlg::OnBnClickedSync2)
	ON_BN_CLICKED(IDC_RINGMOD2, &CSIDSoundDlg::OnBnClickedRingmod2)
	ON_BN_CLICKED(IDC_TEST2, &CSIDSoundDlg::OnBnClickedTest2)
	ON_EN_CHANGE(IDC_ATTACKDECAY2, &CSIDSoundDlg::OnEnChangeAttackdecay2)
	ON_EN_CHANGE(IDC_SUSTAINRELEASE2, &CSIDSoundDlg::OnEnChangeSustainrelease2)
	ON_BN_CLICKED(IDC_RESET2, &CSIDSoundDlg::OnBnClickedReset2)
	ON_EN_CHANGE(IDC_FREQLO3, &CSIDSoundDlg::OnEnChangeFreqlo3)
	ON_EN_CHANGE(IDC_FREQHI3, &CSIDSoundDlg::OnEnChangeFreqhi3)
	ON_EN_CHANGE(IDC_PWLO3, &CSIDSoundDlg::OnEnChangePwlo3)
	ON_EN_CHANGE(IDC_PWHI3, &CSIDSoundDlg::OnEnChangePwhi3)
	ON_CBN_SELCHANGE(IDC_NOTES3, &CSIDSoundDlg::OnCbnSelchangeNotes3)
	ON_CBN_SELCHANGE(IDC_WAVE3, &CSIDSoundDlg::OnCbnSelchangeWave3)
	ON_BN_CLICKED(IDC_GATE3, &CSIDSoundDlg::OnBnClickedGate3)
	ON_BN_CLICKED(IDC_SYNC3, &CSIDSoundDlg::OnBnClickedSync3)
	ON_BN_CLICKED(IDC_RINGMOD3, &CSIDSoundDlg::OnBnClickedRingmod3)
	ON_BN_CLICKED(IDC_TEST3, &CSIDSoundDlg::OnBnClickedTest3)
	ON_EN_CHANGE(IDC_ATTACKDECAY3, &CSIDSoundDlg::OnEnChangeAttackdecay3)
	ON_EN_CHANGE(IDC_SUSTAINRELEASE3, &CSIDSoundDlg::OnEnChangeSustainrelease3)
	ON_BN_CLICKED(IDC_RESET3, &CSIDSoundDlg::OnBnClickedReset3)
	ON_CBN_SELCHANGE(IDC_FC, &CSIDSoundDlg::OnCbnSelchangeFc)
	ON_EN_CHANGE(IDC_FCLO, &CSIDSoundDlg::OnEnChangeFclo)
	ON_EN_CHANGE(IDC_FCHI, &CSIDSoundDlg::OnEnChangeFchi)
	ON_EN_CHANGE(IDC_RES, &CSIDSoundDlg::OnEnChangeRes)
	ON_CBN_SELCHANGE(IDC_MODE, &CSIDSoundDlg::OnCbnSelchangeMode)
	ON_BN_CLICKED(IDC_FILTENABLE, &CSIDSoundDlg::OnBnClickedFiltenable)
	ON_EN_CHANGE(IDC_VOL, &CSIDSoundDlg::OnEnChangeVol)
	ON_BN_CLICKED(IDC_MUTEV1, &CSIDSoundDlg::OnBnClickedMutev1)
	ON_BN_CLICKED(IDC_MUTEV2, &CSIDSoundDlg::OnBnClickedMutev2)
	ON_BN_CLICKED(IDC_MUTEV3, &CSIDSoundDlg::OnBnClickedMutev3)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_FILTV1, &CSIDSoundDlg::OnBnClickedFiltv1)
	ON_BN_CLICKED(IDC_FILTV2, &CSIDSoundDlg::OnBnClickedFiltv2)
	ON_BN_CLICKED(IDC_FILTV3, &CSIDSoundDlg::OnBnClickedFiltv3)
	ON_BN_CLICKED(IDC_FILTEXTIN, &CSIDSoundDlg::OnBnClickedFiltextin)
END_MESSAGE_MAP()


// CSIDSoundDlg message handlers

BOOL CSIDSoundDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	//Make sure all our waveformas are tri at start up
	m_cmbWave1.SetCurSel(0);
	m_cmbWave2.SetCurSel(0);
	m_cmbWave3.SetCurSel(0);
	
	//Make sure the sel is at 50 for all voices at start
	m_cmbNotes1.SetCurSel(50);
	m_cmbNotes2.SetCurSel(50);
	m_cmbNotes3.SetCurSel(50);
	
	//Set all voices to that freq for that sel
	m_mySid.WriteSIDReg(0, SIDNotes[50].LowByte);
	m_mySid.WriteSIDReg(1, SIDNotes[50].HighByte);
	m_mySid.WriteSIDReg(7, SIDNotes[50].LowByte);
	m_mySid.WriteSIDReg(8, SIDNotes[50].HighByte);
	m_mySid.WriteSIDReg(14, SIDNotes[50].LowByte);
	m_mySid.WriteSIDReg(15, SIDNotes[50].HighByte);
	
	//Set all voices waveforms to triangle for the start
	m_mySid.SetWaveForVoice(1, RWSID::kTri, true);
	m_mySid.SetWaveForVoice(2, RWSID::kTri, true);
	m_mySid.SetWaveForVoice(3, RWSID::kTri, true);
	
	//Set the volume to max for testing
	m_strVol = _T("0xf");
	m_mySid.SetVol(0x0f);
	
	//These are here for testing purposes of the filter
	CButton *btnEnableFilter = static_cast<CButton *>(GetDlgItem(IDC_FILTENABLE));
	btnEnableFilter->SetCheck(BST_CHECKED);
	m_mySid.EnableFilter(false);
	
	CString strFreq;
	for (unsigned short i = 0; i < 2048; i++)
	{
		m_FiltFreqs[i].FCLo = i & 0x7;
		m_FiltFreqs[i].FCHi = (i >> 3) & 0xff;
		m_FiltFreqs[i].freq = 20.f + 6.55f * i;
		strFreq.Format(_T("%.2f"), m_FiltFreqs[i].freq);
		m_cmbFC.AddString(strFreq);
	}
	m_cmbFC.SetCurSel(1024);
	m_mySid.SetFilterFCLo(m_FiltFreqs[1024].FCLo);
	m_mySid.SetFilterFCHi(m_FiltFreqs[1024].FCHi);
	CString strFCLo;
	strFCLo.Format(_T("0x%x"), m_FiltFreqs[1024].FCLo);
	CString strFCHi;
	strFCHi.Format(_T("0x%x"), m_FiltFreqs[1024].FCHi);
	m_strFcHi = strFCHi;
	m_strFcLo = strFCLo;

	//m_mySid.SetFilterFreq(7000.f);
	m_strRes = _T("0x3");
	m_mySid.SetFilterRes(0x03);

	m_cmbMode.SetCurSel(0);
	m_mySid.SetFilterMode(RWSID::kLP, true);

	CString strFreqLo;
	CString strFreqHi;
	//Get our integer values as a hex string
	strFreqLo.Format(_T("0x%x"), SIDNotes[50].LowByte);
	strFreqHi.Format(_T("0x%x"), SIDNotes[50].HighByte);

	
	m_strFreqLo1 = strFreqLo;
	m_strFreqHi1 = strFreqHi;
	m_strFreqLo2 = strFreqLo;
	m_strFreqHi2 = strFreqHi;
	m_strFreqLo3 = strFreqLo;
	m_strFreqHi3 = strFreqHi;
	
	m_strPwLo1 = _T("0x3b");
	m_strPwLo2 = _T("0x3b");
	m_strPwLo3 = _T("0x3b");
	m_strPwHi1 = _T("0x3");
	m_strPwHi2 = _T("0x3");
	m_strPwHi3 = _T("0x3");
	m_mySid.SetPulseWidthForVoice(1, 0x3b, 0x3);
	m_mySid.SetPulseWidthForVoice(2, 0x3b, 0x3);
	m_mySid.SetPulseWidthForVoice(3, 0x3b, 0x3);
	
	m_strAttackDecay1 = _T("0x55");
	m_strAttackDecay2 = _T("0x55");
	m_strAttackDecay3 = _T("0x55");
	m_strSustainRelease1 = _T("0xac");
	m_strSustainRelease2 = _T("0xac");
	m_strSustainRelease3 = _T("0xac");
	m_mySid.WriteSIDReg(0x5, 0x55);
	m_mySid.WriteSIDReg(0xc, 0x55);
	m_mySid.WriteSIDReg(0x13, 0x55);
	m_mySid.WriteSIDReg(0x6, 0xac);
	m_mySid.WriteSIDReg(0xd, 0xac);
	m_mySid.WriteSIDReg(0x14, 0xac);
	
	UpdateData(FALSE);
	SetupPortAudio(m_mySid);
	//Lets just have it play
	Pa_StartStream(m_pStream);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CSIDSoundDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CSIDSoundDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CSIDSoundDlg::SetupPortAudio(RWSID &mySid)
{
	PaError err = Pa_Initialize();
	err = Pa_OpenDefaultStream(&m_pStream, 0, 1, paFloat32, 44100, 256, paSidCallback, &m_mySid);
}

void CSIDSoundDlg::OnEnChangeFreqlo1()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwLo1, __T('\0'), 16);
	m_mySid.WriteSIDReg(2, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeFreqhi1()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFreqHi1, __T('\0'), 16);
	m_mySid.WriteSIDReg(1, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangePwlo1()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwLo1, __T('\0'), 16);
	m_mySid.WriteSIDReg(2, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangePwhi1()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwHi1, __T('\0'), 16);
	m_mySid.WriteSIDReg(3, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnCbnSelchangeNotes1()
{
	int nCurSel = m_cmbNotes1.GetCurSel();

	m_mySid.SetFreqForVoice(1, SIDNotes[nCurSel].LowByte, SIDNotes[nCurSel].HighByte);

	CString strFreqLo;
	CString strFreqHi;

	strFreqLo.Format(_T("0x%x"), SIDNotes[nCurSel].LowByte);
	strFreqHi.Format(_T("0x%x"), SIDNotes[nCurSel].HighByte);

	m_strFreqLo1 = strFreqLo;
	m_strFreqHi1 = strFreqHi;

	UpdateData(FALSE);
}

void CSIDSoundDlg::OnCbnSelchangeWave1()
{
	UpdateData(TRUE);
	int nCurSel = m_cmbWave1.GetCurSel();
	switch (nCurSel)
	{
	case 0:
		m_mySid.SetWaveForVoice(1, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(1, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(1, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(1, RWSID::kTri, true);
		break;
	case 1:
		m_mySid.SetWaveForVoice(1, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(1, RWSID::kSaw, true);
		m_mySid.SetWaveForVoice(1, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(1, RWSID::kTri, false);
		break;
	case 2:
		m_mySid.SetWaveForVoice(1, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(1, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(1, RWSID::kPulse, true);
		m_mySid.SetWaveForVoice(1, RWSID::kTri, false);
		break;
	case 3:
		m_mySid.SetWaveForVoice(1, RWSID::kNoise, true);
		m_mySid.SetWaveForVoice(1, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(1, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(1, RWSID::kTri, false);
		break;
	}
}

void CSIDSoundDlg::OnBnClickedGate1()
{
	CButton *btnGate = static_cast<CButton *>(GetDlgItem(IDC_GATE1));

	if ((btnGate->GetState() & 0x0003) == 1)
		m_mySid.SetGateForVoice(1, true);
	if ((btnGate->GetState() & 0x0003) == 0)
		m_mySid.SetGateForVoice(1, false);
}

void CSIDSoundDlg::OnBnClickedSync1()
{
	CButton *btnSync = static_cast<CButton *>(GetDlgItem(IDC_SYNC1));

	if ((btnSync->GetState() & 0x0003) == 1)
		m_mySid.SetSyncForVoice(1, true);
	if ((btnSync->GetState() & 0x0003) == 0)
		m_mySid.SetSyncForVoice(1, false);
}

void CSIDSoundDlg::OnBnClickedRingmod1()
{
	CButton *btnRing = static_cast<CButton *>(GetDlgItem(IDC_RINGMOD1));

	 if ((btnRing->GetState() & 0x0003) == 1)
		m_mySid.SetRingModForVoice(1, true);
	 if ((btnRing->GetState() & 0x0003) == 0)
		 m_mySid.SetRingModForVoice(1, false);
}

void CSIDSoundDlg::OnBnClickedTest1()
{
	CButton *btnTest = static_cast<CButton *>(GetDlgItem(IDC_TEST1));

	if ((btnTest->GetState() & 0x0003) == 1)
		m_mySid.SetTestForVoice(1, true);
	if ((btnTest->GetState() & 0x0003) == 0)
		m_mySid.SetTestForVoice(1, false);
}

void CSIDSoundDlg::OnEnChangeAttackdecay1()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strAttackDecay1, __T('\0'), 16);
	m_mySid.WriteSIDReg(5, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeSustainrelease1()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strSustainRelease1, __T('\0'), 16);
	m_mySid.WriteSIDReg(6, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnBnClickedReset1()
{
	m_mySid.ResetVoice(1);
}

void CSIDSoundDlg::OnEnChangeFreqlo2()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFreqLo2, __T('\0'), 16);
	m_mySid.WriteSIDReg(7, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeFreqhi2()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFreqHi2, __T('\0'), 16);
	m_mySid.WriteSIDReg(8, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangePwlo2()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwLo2, __T('\0'), 16);
	m_mySid.WriteSIDReg(9, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangePwhi2()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwHi2, __T('\0'), 16);
	m_mySid.WriteSIDReg(9, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnCbnSelchangeNotes2()
{
	int nCurSel = m_cmbNotes2.GetCurSel();

	m_mySid.SetFreqForVoice(2, SIDNotes[nCurSel].LowByte, SIDNotes[nCurSel].HighByte);

	CString strFreqLo;
	CString strFreqHi;

	strFreqLo.Format(_T("0x%x"), SIDNotes[nCurSel].LowByte);
	strFreqHi.Format(_T("0x%x"), SIDNotes[nCurSel].HighByte);

	m_strFreqLo2 = strFreqLo;
	m_strFreqHi2 = strFreqHi;

	UpdateData(FALSE);
}

void CSIDSoundDlg::OnCbnSelchangeWave2()
{
	UpdateData(TRUE);
	int nCurSel = m_cmbWave2.GetCurSel();
	switch (nCurSel)
	{
	case 0:
		m_mySid.SetWaveForVoice(2, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(2, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(2, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(2, RWSID::kTri, true);
		break;
	case 1:
		m_mySid.SetWaveForVoice(2, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(2, RWSID::kSaw, true);
		m_mySid.SetWaveForVoice(2, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(2, RWSID::kTri, false);
		break;
	case 2:
		m_mySid.SetWaveForVoice(2, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(2, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(2, RWSID::kPulse, true);
		m_mySid.SetWaveForVoice(2, RWSID::kTri, false);
		break;
	case 3:
		m_mySid.SetWaveForVoice(2, RWSID::kNoise, true);
		m_mySid.SetWaveForVoice(2, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(2, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(2, RWSID::kTri, false);
		break;
	}
}

void CSIDSoundDlg::OnBnClickedGate2()
{
	CButton *btnGate = static_cast<CButton *>(GetDlgItem(IDC_GATE2));

	if ((btnGate->GetState() & 0x0003) == 1)
		m_mySid.SetGateForVoice(2, true);
	if ((btnGate->GetState() & 0x0003) == 0)
		m_mySid.SetGateForVoice(2, false);
}

void CSIDSoundDlg::OnBnClickedSync2()
{
	CButton *btnSync = static_cast<CButton *>(GetDlgItem(IDC_SYNC2));

	if ((btnSync->GetState() & 0x0003) == 1)
		m_mySid.SetSyncForVoice(2, true);
	if ((btnSync->GetState() & 0x0003) == 0)
		m_mySid.SetSyncForVoice(2, false);
}

void CSIDSoundDlg::OnBnClickedRingmod2()
{
	CButton *btnRing = static_cast<CButton *>(GetDlgItem(IDC_RINGMOD2));

	 if ((btnRing->GetState() & 0x0003) == 1)
		m_mySid.SetRingModForVoice(2, true);
	 if ((btnRing->GetState() & 0x0003) == 0)
		 m_mySid.SetRingModForVoice(2, false);
}

void CSIDSoundDlg::OnBnClickedTest2()
{
	CButton *btnTest = static_cast<CButton *>(GetDlgItem(IDC_TEST2));

	if ((btnTest->GetState() & 0x0003) == 1)
		m_mySid.SetTestForVoice(2, true);
	if ((btnTest->GetState() & 0x0003) == 0)
		m_mySid.SetTestForVoice(2, false);
}

void CSIDSoundDlg::OnEnChangeAttackdecay2()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strAttackDecay2, __T('\0'), 16);
	m_mySid.WriteSIDReg(12, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeSustainrelease2()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strSustainRelease2, __T('\0'), 16);
	m_mySid.WriteSIDReg(13, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnBnClickedReset2()
{
	m_mySid.ResetVoice(2);
}

void CSIDSoundDlg::OnEnChangeFreqlo3()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFreqLo3, __T('\0'), 16);
	m_mySid.WriteSIDReg(14, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeFreqhi3()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFreqHi3, __T('\0'), 16);
	m_mySid.WriteSIDReg(15, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangePwlo3()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwLo3, __T('\0'), 16);
	m_mySid.WriteSIDReg(16, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangePwhi3()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strPwHi3, __T('\0'), 16);
	m_mySid.WriteSIDReg(17, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnCbnSelchangeNotes3()
{
	int nCurSel = m_cmbNotes3.GetCurSel();

	m_mySid.SetFreqForVoice(3, SIDNotes[nCurSel].LowByte, SIDNotes[nCurSel].HighByte);

	CString strFreqLo;
	CString strFreqHi;

	strFreqLo.Format(_T("0x%x"), SIDNotes[nCurSel].LowByte);
	strFreqHi.Format(_T("0x%x"), SIDNotes[nCurSel].HighByte);

	m_strFreqLo3 = strFreqLo;
	m_strFreqHi3 = strFreqHi;

	UpdateData(FALSE);
}

void CSIDSoundDlg::OnCbnSelchangeWave3()
{
	UpdateData(TRUE);
	int nCurSel = m_cmbWave3.GetCurSel();
	switch (nCurSel)
	{
	case 0:
		m_mySid.SetWaveForVoice(3, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(3, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(3, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(3, RWSID::kTri, true);
		break;
	case 1:
		m_mySid.SetWaveForVoice(3, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(3, RWSID::kSaw, true);
		m_mySid.SetWaveForVoice(3, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(3, RWSID::kTri, false);
		break;
	case 2:
		m_mySid.SetWaveForVoice(3, RWSID::kNoise, false);
		m_mySid.SetWaveForVoice(3, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(3, RWSID::kPulse, true);
		m_mySid.SetWaveForVoice(3, RWSID::kTri, false);
		break;
	case 3:
		m_mySid.SetWaveForVoice(3, RWSID::kNoise, true);
		m_mySid.SetWaveForVoice(3, RWSID::kSaw, false);
		m_mySid.SetWaveForVoice(3, RWSID::kPulse, false);
		m_mySid.SetWaveForVoice(3, RWSID::kTri, false);
		break;
	}
}

void CSIDSoundDlg::OnBnClickedGate3()
{
	CButton *btnGate = static_cast<CButton *>(GetDlgItem(IDC_GATE3));

	if ((btnGate->GetState() & 0x0003) == 1)
		m_mySid.SetGateForVoice(3, true);
	if ((btnGate->GetState() & 0x0003) == 0)
		m_mySid.SetGateForVoice(3, false);
}

void CSIDSoundDlg::OnBnClickedSync3()
{
	CButton *btnSync = static_cast<CButton *>(GetDlgItem(IDC_SYNC3));

	if ((btnSync->GetState() & 0x0003) == 1)
		m_mySid.SetSyncForVoice(3, true);
	if ((btnSync->GetState() & 0x0003) == 0)
		m_mySid.SetSyncForVoice(3, false);
}

void CSIDSoundDlg::OnBnClickedRingmod3()
{
	CButton *btnRing = static_cast<CButton *>(GetDlgItem(IDC_RINGMOD3));

	 if ((btnRing->GetState() & 0x0003) == 1)
		m_mySid.SetRingModForVoice(3, true);
	 if ((btnRing->GetState() & 0x0003) == 0)
		 m_mySid.SetRingModForVoice(3, false);
}

void CSIDSoundDlg::OnBnClickedTest3()
{
	CButton *btnTest = static_cast<CButton *>(GetDlgItem(IDC_TEST3));

	if ((btnTest->GetState() & 0x0003) == 1)
		m_mySid.SetTestForVoice(3, true);
	if ((btnTest->GetState() & 0x0003) == 0)
		m_mySid.SetTestForVoice(3, false);
}

void CSIDSoundDlg::OnEnChangeAttackdecay3()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strAttackDecay3, __T('\0'), 16);
	m_mySid.WriteSIDReg(19, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeSustainrelease3()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strSustainRelease3, __T('\0'), 16);
	m_mySid.WriteSIDReg(20, static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnBnClickedReset3()
{
	// TODO: Add your control notification handler code here
}

void CSIDSoundDlg::OnCbnSelchangeFc()
{
	int nCurSel = m_cmbFC.GetCurSel();
	m_mySid.SetFilterFCLo(m_FiltFreqs[nCurSel].FCLo);
	m_mySid.SetFilterFCHi(m_FiltFreqs[nCurSel].FCHi);

	CString strFCLo;
	strFCLo.Format(_T("0x%x"), m_FiltFreqs[nCurSel].FCLo);
	CString strFCHi;
	strFCHi.Format(_T("0x%x"), m_FiltFreqs[nCurSel].FCHi);
	m_strFcHi = strFCHi;
	m_strFcLo = strFCLo;
	UpdateData(FALSE);
}

void CSIDSoundDlg::OnEnChangeFclo()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFcLo, __T('\0'), 16);
	m_mySid.SetFilterFCLo(static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeFchi()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strFcHi, __T('\0'), 16);
	m_mySid.SetFilterFCHi(static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnEnChangeRes()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strRes, __T('\0'), 16);
	m_mySid.SetFilterRes(static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnCbnSelchangeMode()
{
	UpdateData(TRUE);
	int nCurSel = m_cmbMode.GetCurSel();
	switch (nCurSel)
	{
	case 0:
		m_mySid.SetFilterMode(RWSID::k3Off, false);
		m_mySid.SetFilterMode(RWSID::kHP, false);
		m_mySid.SetFilterMode(RWSID::kBP, false);
		m_mySid.SetFilterMode(RWSID::kLP, true);
		break;
	case 1:
		m_mySid.SetFilterMode(RWSID::k3Off, false);
		m_mySid.SetFilterMode(RWSID::kHP, false);
		m_mySid.SetFilterMode(RWSID::kBP, true);
		m_mySid.SetFilterMode(RWSID::kLP, false);
		break;
	case 2:
		m_mySid.SetFilterMode(RWSID::k3Off, false);
		m_mySid.SetFilterMode(RWSID::kHP, true);
		m_mySid.SetFilterMode(RWSID::kBP, false);
		m_mySid.SetFilterMode(RWSID::kLP, false);
		break;
	case 3:
		m_mySid.SetFilterMode(RWSID::k3Off, true);
		m_mySid.SetFilterMode(RWSID::kHP, false);
		m_mySid.SetFilterMode(RWSID::kBP, false);
		m_mySid.SetFilterMode(RWSID::kLP, false);
		break;
	}
}

void CSIDSoundDlg::OnBnClickedFiltenable()
{
	CButton *btnFiltEna = static_cast<CButton *>(GetDlgItem(IDC_FILTENABLE));

	if ((btnFiltEna->GetState() & 0x0003) == 1)
		m_mySid.EnableFilter(true);
	if ((btnFiltEna->GetState() & 0x0003) == 0)
		m_mySid.EnableFilter(false);
}

void CSIDSoundDlg::OnEnChangeVol()
{
	UpdateData(TRUE);
	unsigned long ulStrToHex = _tcstoul(m_strVol, __T('\0'), 16);
	m_mySid.SetVol(static_cast<unsigned char>(ulStrToHex));
}

void CSIDSoundDlg::OnBnClickedMutev1()
{
	CButton *btnMuteV1 = static_cast<CButton *>(GetDlgItem(IDC_MUTEV1));

	if ((btnMuteV1->GetState() & 0x0003) == 1)
		m_mySid.SetMuteForVoice(1, true);
	if ((btnMuteV1->GetState() & 0x0003) == 0)
		m_mySid.SetMuteForVoice(1, false);
}

void CSIDSoundDlg::OnBnClickedMutev2()
{
	CButton *btnMuteV2 = static_cast<CButton *>(GetDlgItem(IDC_MUTEV2));

	if ((btnMuteV2->GetState() & 0x0003) == 1)
		m_mySid.SetMuteForVoice(2, true);
	if ((btnMuteV2->GetState() & 0x0003) == 0)
		m_mySid.SetMuteForVoice(2, false);
}

void CSIDSoundDlg::OnBnClickedMutev3()
{
	CButton *btnMuteV3 = static_cast<CButton *>(GetDlgItem(IDC_MUTEV3));

	if ((btnMuteV3->GetState() & 0x0003) == 1)
		m_mySid.SetMuteForVoice(3, true);
	if ((btnMuteV3->GetState() & 0x0003) == 0)
		m_mySid.SetMuteForVoice(3, false);
}

void CSIDSoundDlg::OnDestroy()
{
	CDialog::OnDestroy();

	Pa_StopStream(m_pStream);
	Pa_CloseStream(m_pStream);
	Pa_Terminate();
}

void CSIDSoundDlg::OnBnClickedFiltv1()
{
	CButton *btnFiltV1 = static_cast<CButton *>(GetDlgItem(IDC_FILTV1));

	if ((btnFiltV1->GetState() & 0x0003) == 1)
		m_mySid.SetFilterRouting(1, true);
	if ((btnFiltV1->GetState() & 0x0003) == 0)
		m_mySid.SetFilterRouting(1, false);
}

void CSIDSoundDlg::OnBnClickedFiltv2()
{
	CButton *btnFiltV2 = static_cast<CButton *>(GetDlgItem(IDC_FILTV2));

	if ((btnFiltV2->GetState() & 0x0003) == 1)
		m_mySid.SetFilterRouting(2, true);
	if ((btnFiltV2->GetState() & 0x0003) == 0)
		m_mySid.SetFilterRouting(2, false);
}

void CSIDSoundDlg::OnBnClickedFiltv3()
{
	CButton *btnFiltV3 = static_cast<CButton *>(GetDlgItem(IDC_FILTV3));

	if ((btnFiltV3->GetState() & 0x0003) == 1)
		m_mySid.SetFilterRouting(3, true);
	if ((btnFiltV3->GetState() & 0x0003) == 0)
		m_mySid.SetFilterRouting(3, false);
}

void CSIDSoundDlg::OnBnClickedFiltextin()
{
	// TODO: Add your control notification handler code here
}
